package repository

import (
	"fitness/go-admin/internal/model"
	"time"

	"gorm.io/gorm"
)

// ChatStatisticsRepository 客服统计数据访问层
type ChatStatisticsRepository struct {
	db *gorm.DB
}

// NewChatStatisticsRepository 创建客服统计仓库
func NewChatStatisticsRepository(db *gorm.DB) *ChatStatisticsRepository {
	return &ChatStatisticsRepository{db: db}
}

// GetStaffStatistics 获取客服统计数据
func (r *ChatStatisticsRepository) GetStaffStatistics(staffID uint, startDate, endDate time.Time) (*model.SessionStatistics, error) {
	var stats model.SessionStatistics

	// 使用子查询计算平均响应时间
	err := r.db.Raw(`
		SELECT 
			COUNT(*) as total_sessions,
			SUM(CASE WHEN status = 'ACTIVE' THEN 1 ELSE 0 END) as active_sessions,
			SUM(CASE WHEN status = 'CLOSED' THEN 1 ELSE 0 END) as closed_sessions,
			AVG(CASE 
				WHEN rating IS NOT NULL THEN rating 
				ELSE NULL 
			END) as avg_rating,
			AVG(CASE 
				WHEN closed_at IS NOT NULL AND created_at IS NOT NULL 
				THEN TIMESTAMPDIFF(SECOND, created_at, closed_at) / 60.0
				ELSE NULL 
			END) as avg_session_duration
		FROM chat_sessions 
		WHERE staff_id = ? 
		AND created_at >= ? 
		AND created_at < ?
	`, staffID, startDate, endDate.Add(24*time.Hour)).Scan(&stats).Error

	return &stats, err
}

// GetAverageResponseTime 计算平均响应时间（客服首次回复时间）
func (r *ChatStatisticsRepository) GetAverageResponseTime(staffID uint, startDate, endDate time.Time) (float64, error) {
	var avgResponseTime float64

	// 计算客服首次回复的平均时间（会话创建到客服第一次发消息的时间差）
	err := r.db.Raw(`
		SELECT AVG(response_time) as avg_response_time
		FROM (
			SELECT TIMESTAMPDIFF(SECOND, cs.created_at, MIN(cm.created_at)) as response_time
			FROM chat_sessions cs
			INNER JOIN chat_messages cm ON cs.id = cm.session_id
			WHERE cs.staff_id = ?
			AND cs.created_at >= ?
			AND cs.created_at < ?
			AND cm.sender_type = 'STAFF'
			AND cm.sender_id = ?
			GROUP BY cs.id
		) as response_times
	`, staffID, startDate, endDate.Add(24*time.Hour), staffID).Scan(&avgResponseTime).Error

	return avgResponseTime, err
}

// GetTotalMessages 获取客服发送的总消息数
func (r *ChatStatisticsRepository) GetTotalMessages(staffID uint, startDate, endDate time.Time) (int64, error) {
	var count int64

	err := r.db.Model(&model.ChatMessage{}).
		Joins("INNER JOIN chat_sessions ON chat_messages.session_id = chat_sessions.id").
		Where("chat_messages.sender_type = ?", "STAFF").
		Where("chat_messages.sender_id = ?", staffID).
		Where("chat_sessions.staff_id = ?", staffID).
		Where("chat_messages.created_at >= ?", startDate).
		Where("chat_messages.created_at < ?", endDate.Add(24*time.Hour)).
		Count(&count).Error

	return count, err
}

// GetRatingDistribution 获取评分分布
func (r *ChatStatisticsRepository) GetRatingDistribution(staffID uint, startDate, endDate time.Time) (map[string]int64, error) {
	type RatingCount struct {
		Rating int   `gorm:"column:rating"`
		Count  int64 `gorm:"column:count"`
	}

	var results []RatingCount
	err := r.db.Model(&model.ChatSession{}).
		Select("rating, COUNT(*) as count").
		Where("staff_id = ?", staffID).
		Where("created_at >= ?", startDate).
		Where("created_at < ?", endDate.Add(24*time.Hour)).
		Where("rating IS NOT NULL").
		Group("rating").
		Scan(&results).Error

	if err != nil {
		return nil, err
	}

	// 转换为 map
	distribution := make(map[string]int64)
	for _, result := range results {
		key := ""
		switch result.Rating {
		case 1:
			key = "1star"
		case 2:
			key = "2star"
		case 3:
			key = "3star"
		case 4:
			key = "4star"
		case 5:
			key = "5star"
		}
		if key != "" {
			distribution[key] = result.Count
		}
	}

	return distribution, nil
}

// GetSessionsPerDay 获取每日会话数
func (r *ChatStatisticsRepository) GetSessionsPerDay(staffID uint, startDate, endDate time.Time) (map[string]int64, error) {
	type DayCount struct {
		Date  string `gorm:"column:date"`
		Count int64  `gorm:"column:count"`
	}

	var results []DayCount
	err := r.db.Model(&model.ChatSession{}).
		Select("DATE(created_at) as date, COUNT(*) as count").
		Where("staff_id = ?", staffID).
		Where("created_at >= ?", startDate).
		Where("created_at < ?", endDate.Add(24*time.Hour)).
		Group("DATE(created_at)").
		Order("date ASC").
		Scan(&results).Error

	if err != nil {
		return nil, err
	}

	// 转换为 map
	sessionsPerDay := make(map[string]int64)
	for _, result := range results {
		sessionsPerDay[result.Date] = result.Count
	}

	return sessionsPerDay, nil
}

